package com.dcms.staticizing.service.impl;

import com.dcms.staticizing.service.IStaticizingService;
import com.dcms.util.StaticizingUtil;
import org.apache.commons.lang.StringUtils;
import org.apache.log4j.Logger;
import org.ehcache.Cache;
import org.ehcache.PersistentCacheManager;
import org.ehcache.config.builders.CacheConfigurationBuilder;
import org.ehcache.config.builders.CacheManagerBuilder;
import org.ehcache.config.builders.ResourcePoolsBuilder;
import org.ehcache.config.units.MemoryUnit;
import org.springframework.stereotype.Service;

import javax.servlet.http.HttpServletRequest;
import java.io.File;
import java.util.*;

/**
 * ClassName: SimpleStaticizingService
 * 所属功能模块: 静态化页面功能的一个简单实现类
 * 功能描述:
 *          使用EhCache来管理静态化的页面
 *
 * @author zhouyijin
 * @Date 2018年02月20日 15:32
 * @since Ver 1.0
 */
@Service
public class SimpleStaticizingService implements IStaticizingService {

    private final static Logger LOGGER = Logger.getLogger(SimpleStaticizingService.class);

    private final static String CACHE_NAME = "SimpleStaticizingServiceCache";

    private static PersistentCacheManager persistentCacheManager;

    static {
        LOGGER.info("页面静态化模块缓存,正在初始化...");
        //缓存文件和SimpleStaticizingService.class文件放在一起,随便放的
        String cacheFilePath = SimpleStaticizingService.class.getResource("").getPath();
        File cacheFile = new File(cacheFilePath);
        LOGGER.info("页面静态化模块缓存文件路径: " + cacheFilePath);
        //初始化缓存
        try {
            persistentCacheManager = CacheManagerBuilder.newCacheManagerBuilder()
                    .with(CacheManagerBuilder.persistence(cacheFile))
                    .withCache(CACHE_NAME,
                            CacheConfigurationBuilder.newCacheConfigurationBuilder(String.class, String.class,
                                    ResourcePoolsBuilder.newResourcePoolsBuilder()
                                            .heap(100, MemoryUnit.MB) //最快的缓存
                                            .offheap(200, MemoryUnit.MB)    //较快的缓存
                                            .disk(500, MemoryUnit.MB, true) //保存在磁盘上
                            )
                    ).build(true);
            LOGGER.info("页面静态化模块缓存,初始化完毕!");
        }catch (Exception e){
            e.printStackTrace();
            LOGGER.error("页面静态化模块缓存,初始化失败,关闭此功能!");
        }
    }

    /**
     * 将指定页面静态化,
     * 此方法是个耗时任务
     * @param url
     */
    @Override
    public void staticizing(HttpServletRequest request, String url) {
        if (persistentCacheManager==null||request==null){
            throw new StaticizingException("页面静态化模块未能初始化,静态化模块已关闭!");
        }
        LOGGER.info("页面静态化: "+url+" --> 操作中");
        if (!url.startsWith("/")){
            url = "/"+url;
        }
        if (getCache().containsKey(url)){
            throw new StaticizingException("页面静态化: "+url+" --> 操作失败! 已静态化,请勿重复操作!");
        }
        //获取要静态化的页面的实际url
        String accessUrl = request.getScheme()+"://"+request.getServerName()+":"+request.getServerPort()+request.getContextPath()+url;
        String html = StaticizingUtil.getHtml(accessUrl);
        if (StringUtils.isNotEmpty(html)){
            //将静态化后的html页面保存到ehCache中
            getCache().put(url,html);
            LOGGER.info("页面静态化: "+url+" --> 操作完成");
        }else {
            LOGGER.error("页面静态化: "+url+" --> 操作失败! 未能获取到页面");
            throw new StaticizingException("页面静态化: "+url+" --> 操作失败! 未能获取到页面");
        }

    }

    /**
     * 获取所有已经静态化的页面
     * @return
     */
    @Override
    public Map<String,String> getAllStaticizingHtml() {
        if (persistentCacheManager==null){
            throw new StaticizingException("页面静态化模块未能初始化,静态化模块已关闭!");
        }
        Iterator<Cache.Entry<String,String>> allEntry = getCache().iterator();
        Map<String,String> result = new HashMap();
        while (allEntry.hasNext()){
            Cache.Entry<String,String> entry = allEntry.next();
            result.put(entry.getKey(),entry.getValue());
        }
        return result;
    }

    @Override
    public Set<String> getAllStaticizingUrls() {
        if (persistentCacheManager==null){
            throw new StaticizingException("页面静态化模块未能初始化,静态化模块已关闭!");
        }
        Iterator<Cache.Entry<String,String>> allEntry = getCache().iterator();
        Set<String> allUrl = new HashSet();
        while (allEntry.hasNext()){
            allUrl.add(allEntry.next().getKey());
        }
        return allUrl;
    }

    /**
     * 获取指定页面的静态化内容,
     * @param url 这个url是相对路径不包括协议,端口,和域名
     * @return
     */
    @Override
    public String getStaticizedHtml(String url) {
        if (persistentCacheManager==null){
            return null;
        }
        String html = getCache().get(url);
        if (StringUtils.isNotEmpty(html)){
            LOGGER.info("页面静态化: "+url+" --> 使用静态化页面");
            return html;
        }
        return null;
    }

    /**
     * 移除指定页面的静态化内容
     * @param url
     */
    @Override
    public void removeStaticizedHtml(String url) {
        if (persistentCacheManager==null){
            throw new StaticizingException("页面静态化模块未能初始化,静态化模块已关闭!");
        }
        getCache().remove(url);
        LOGGER.info("页面静态化: "+url+" --> 取消静态化");
    }


    private Cache<String,String> getCache(){
        return persistentCacheManager.getCache(CACHE_NAME,String.class,String.class);
    }


    /**
     * 用来标识是哪种类型的错误
     */
    private static class StaticizingException extends RuntimeException{
        public StaticizingException(){
            super();
        }
        public StaticizingException(String msg){
            super(msg);
        }
    }

}
